/*
 *  BlipUpInterface.cpp
 *  BlipUp
 *
 *  Created by Pete Bunting on 11/01/2012.
 *  Copyright 2012 Pete Bunting.
 * 
 *  BlipUp is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  BlipUp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with BlipUp.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "BlipUpInterface.h"

namespace blipup
{

    BlipUpInterface::BlipUpInterface()
    {
        authenticationSet = false;
        username = "";
        passToken = "";
        
        progSettings = new QSettings(QSettings::UserScope, "com.mac.blipup", "BlipUp", this);
        progSettings->beginGroup("UserInfo");
		username = progSettings->value("Username", "").toString();
		passToken = progSettings->value("PassToken", "").toString();
		progSettings->endGroup();
        
        if((username != "") & (passToken != ""))
        {
            authenticationSet = true;
        }
        
        this->setWindowTitle("BlipUp");
		
		// Set Minimum size of window
		setMinimumSize(400, 200);
        
        /**************** Top Username and login ***************************/
        hLayoutLogin = new QHBoxLayout();
        
        loginButton = new QPushButton("Login");
        QObject::connect(loginButton, SIGNAL(clicked()), this, SLOT(login()));
        logoutButton = new QPushButton("Logout");
        QObject::connect(logoutButton, SIGNAL(clicked()), this, SLOT(logout()));
        
        if(authenticationSet)
        {
            QString usernameText = QString("You are currently login in as ") + username; 
            usernameLabel = new QLabel(usernameText);
            loginButton->setEnabled(false);
            logoutButton->setEnabled(true);
        }
        else
        {
            usernameLabel = new QLabel("You are not currently login...");
            loginButton->setEnabled(true);
            logoutButton->setEnabled(false);
        }
        
        hLayoutLogin->insertWidget(0, usernameLabel);
        hLayoutLogin->insertStretch(1);
        hLayoutLogin->insertWidget(2, loginButton);
        hLayoutLogin->insertWidget(3, logoutButton);
        
        /**************** Left hand controls and list ***************************/
        blipList = new QListWidget();
        QObject::connect(blipList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectBlipInList(QListWidgetItem*)));
        
        QPushButton *addBlipButton = new QPushButton("Add Blip");
		QObject::connect(addBlipButton, SIGNAL(clicked()), this, SLOT(addBlip()));
		//addBlipButton->setMaximumSize(100, 30);
        
        QPushButton *removeBlipButton = new QPushButton("Remove Blip");
		QObject::connect(removeBlipButton, SIGNAL(clicked()), this, SLOT(removeBlip()));
		//removeBlipButton->setMaximumSize(100, 30);

        QPushButton *saveBlipsButton = new QPushButton("Save");
		QObject::connect(saveBlipsButton, SIGNAL(clicked()), this, SLOT(saveBlips()));
        
        QPushButton *openBlipsButton = new QPushButton("Open");
		QObject::connect(openBlipsButton, SIGNAL(clicked()), this, SLOT(openBlips()));
        
        QPushButton *submitBlipsButton = new QPushButton("Submit");
		QObject::connect(submitBlipsButton, SIGNAL(clicked()), this, SLOT(submitBlips()));
		//submitBlipsButton->setMaximumSize(100, 30);

        
        QVBoxLayout *vLayoutControls = new QVBoxLayout();
        vLayoutControls->insertWidget(0, blipList);
        vLayoutControls->insertWidget(1, addBlipButton);
        vLayoutControls->insertWidget(2, removeBlipButton);
        vLayoutControls->insertWidget(3, saveBlipsButton);
        vLayoutControls->insertWidget(4, openBlipsButton);
        vLayoutControls->insertWidget(5, submitBlipsButton);
        
        /**************** Right hand controls and info editor ***************************/
        imageView = new QLabel();
        imageView->setMaximumWidth(600);
        descriptionTextEdit = new QPlainTextEdit();
        titleTextLine = new QLineEdit();
        tagsTextLine = new QLineEdit();
        
        QVBoxLayout *vDetailsLayout = new QVBoxLayout();
        vDetailsLayout->insertWidget(0, imageView);
        vDetailsLayout->insertWidget(1, new QLabel("Title:"));
        vDetailsLayout->insertWidget(2, titleTextLine);
        vDetailsLayout->insertWidget(3, new QLabel("Description:"));
        vDetailsLayout->insertWidget(4, descriptionTextEdit);
        vDetailsLayout->insertWidget(5, new QLabel("Tags:"));
        vDetailsLayout->insertWidget(6, tagsTextLine);
        
        /*********** Joint left and right sections **************/
        QHBoxLayout *hLayoutMain = new QHBoxLayout();
		hLayoutMain->insertLayout(0, vLayoutControls, 0);
		hLayoutMain->insertLayout(1, vDetailsLayout, 1);
        
        /*********** Add main and top sections and add to MainWindow **************/
        centralWidget = new QWidget(this);
		centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
        layoutOverall = new QVBoxLayout(centralWidget);
        layoutOverall->insertLayout(0, hLayoutLogin, 0);
		layoutOverall->insertLayout(1, hLayoutMain, 1);
        
        setCentralWidget(centralWidget);
        
        
        blips = new vector<BlipDetails*>();
        currentBlip = NULL;
        currentImage = NULL;
        
        QTime time = QTime::currentTime();
        qsrand ( time.msec() );
    }
    
	void BlipUpInterface::addImage(QString file)
    {
        //std::cout << "File: " << file.toStdString() << std::endl;
        // Find the Date of capture!
        ExifData *exifData = exif_data_new_from_file (file.toStdString().c_str());
        ExifEntry *dateTimeEntry = exif_data_get_entry(exifData, EXIF_TAG_DATE_TIME_ORIGINAL);        
        char *dateTimeInOutVal = new char[255];
        const char *dateTimeOutVal = exif_entry_get_value(dateTimeEntry, dateTimeInOutVal, 255);
        QString dateTimeStr = QString::fromStdString(string(dateTimeOutVal));
        //delete[] dateTimeInOutVal;
        //delete[] dateTimeOutVal;
        //exif_entry_free(dateTimeEntry);
        //exif_data_free(exifData);
        
        //std::cout << "Date and Time: " << dateTimeStr.toStdString() << std::endl;
        
        QDateTime dateTime = QDateTime::fromString(dateTimeStr, "yyyy:MM:dd hh:mm:ss");
        QDate captureDate = dateTime.date();
        //std::cout << "Year = " << captureDate.year() << std::endl;
        //std::cout << "Month = " << captureDate.month() << std::endl;
        //std::cout << "Day = " << captureDate.day() << std::endl;
        
        BlipDetails *blip = new BlipDetails();
        blip->label = captureDate.toString("yyyy-MM-dd");
        blip->filepath = file;
        blip->date = dateTime;
        blip->title = QString("Photo Taken on ") + captureDate.toString("yyyy-MM-dd");
        blip->description = "Insert Description";
        blip->tags = "";
        
        blips->push_back(blip);
        currentBlip = blip;
        
        QListWidgetItem *newItem = new QListWidgetItem;
        newItem->setText(blip->label);
        blipList->insertItem(0, newItem);
    }
    
    void BlipUpInterface::resizeEvent(QResizeEvent * event)
    {   
        if(currentImage != NULL)
        {
            if(imageView->width() < 600)
            {
                imageView->setPixmap(QPixmap::fromImage(currentImage->scaledToWidth(imageView->width(), Qt::SmoothTransformation)));
            }
        }
    }
    
    void BlipUpInterface::setAuthXML(QString xmlStr)
    {
        BlipUpXMLParsing parseXML;
        try 
        {
            if(parseXML.parseAuthXML(xmlStr, &username, &passToken))
            {
                authenticationSet = true;
                
                //cout << "Username: " << username.toStdString() << endl;
                //cout << "Passcode: " << passToken.toStdString() << endl;
                
                progSettings->beginGroup("UserInfo");
                progSettings->setValue("Username", username);
                progSettings->setValue("PassToken", passToken);
                progSettings->endGroup();
            }
            else
            {
                // Do something with error!
                QString error = parseXML.getErrorMessage(xmlStr);
                cerr << "ERROR: " << error.toStdString() << endl;
            }
        } 
        catch (BlipUpException &e) 
        {
            // Do something with error!
            cerr << "ERROR: " << e.what() << endl;
        }
    }
    
    void BlipUpInterface::addBlip()
    {
        if(currentBlip != NULL)
        {
            currentBlip->title = titleTextLine->text();
            currentBlip->description = descriptionTextEdit->toPlainText();
            currentBlip->tags = tagsTextLine->text();
        }
        
        QFileDialog fileDialog;
		fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
		fileDialog.setWindowTitle("Open Image");
        fileDialog.setFileMode(QFileDialog::ExistingFiles);
		
		QStringList filters;
		filters << "JPG File (*.jpg)";
		fileDialog.setNameFilters(filters);
		if(fileDialog.exec() == QDialog::Accepted)
		{
			QStringList files = fileDialog.selectedFiles();
            for(int i = 0; i < files.size(); ++i)
            {
                this->addImage(files[i]);
            }
		}
        
        descriptionTextEdit->setPlainText(currentBlip->description);
        titleTextLine->setPlaceholderText(currentBlip->title);
        if(currentImage == NULL)
        {
            currentImage = new QImage;
        }
        currentImage->load(currentBlip->filepath);
        imageView->setPixmap(QPixmap::fromImage(currentImage->scaledToWidth(imageView->width(), Qt::SmoothTransformation)));
    }
    
    void BlipUpInterface::removeBlip()
    {
        if(currentBlip != NULL)
        {
            QString currentLabel = currentBlip->label;
            for(vector<BlipDetails*>::iterator iterBlips = blips->begin(); iterBlips != blips->end(); ++iterBlips)
            {
                if((*iterBlips)->label == currentLabel)
                {
                    delete *iterBlips;
                    iterBlips = blips->erase(iterBlips);
                    
                    QListWidgetItem *tmpItem = blipList->takeItem(blipList->currentRow());
                    if(tmpItem != NULL)
                    {
                        delete tmpItem;
                    }
                }
            }
            
            currentBlip = NULL;
            imageView->clear();
            descriptionTextEdit->clear();
            titleTextLine->clear();
            tagsTextLine->clear();
            
            if(blipList->count() > 0)
            {
                this->selectBlipInList(blipList->currentItem());
            }
        }        
    }
    
    void BlipUpInterface::submitBlips()
    {
        if(currentBlip != NULL)
        {
            currentBlip->title = titleTextLine->text();
            currentBlip->description = descriptionTextEdit->toPlainText();
            currentBlip->tags = tagsTextLine->text();
        }
        
        // Check whether already Authenticated if not Authenticate with blipfoto...
        if(!authenticationSet)
        {
            // Authenticate...
            this->login();
        }
        
        if(!blips->empty())
        {
            BlipUpSubmittingDialog *submitFeedbackDialog = new BlipUpSubmittingDialog(this, blips, username, passToken);
            submitFeedbackDialog->exec();
        }
    }
    
    void BlipUpInterface::saveBlips()
    {
        if(currentBlip != NULL)
        {
            currentBlip->title = titleTextLine->text();
            currentBlip->description = descriptionTextEdit->toPlainText();
            currentBlip->tags = tagsTextLine->text();
        }
        
        QFileDialog fileDialog;
		fileDialog.setAcceptMode(QFileDialog::AcceptSave);
		fileDialog.setWindowTitle("Save Blips");
        fileDialog.setFileMode(QFileDialog::AnyFile);
		
		QStringList filters;
		filters << "BUP File (*.bup)";
		fileDialog.setNameFilters(filters);
		if(fileDialog.exec() == QDialog::Accepted)
		{
			QStringList files = fileDialog.selectedFiles();
            if(files.size() == 1)
            {
                const QString outFile = files[0];
                cout << "Output File = " << outFile.toStdString() << endl;
                
                // Create XML file
                
                QDomDocument doc("BlipUpDoc");
                QDomElement rootTag = doc.createElement("BlipUpBlips");
                doc.appendChild(rootTag);
                                
                // Iterate through an write all blips
                for(vector<BlipDetails*>::iterator iterBlips = blips->begin(); iterBlips != blips->end(); ++iterBlips)
                {
                    QDomElement blipTag = doc.createElement("blip");
                    rootTag.appendChild(blipTag);
                    
                    QDomElement dateTag = doc.createElement("date");
                    QDomText dateText = doc.createTextNode((*iterBlips)->label);
                    dateTag.appendChild(dateText);
                    
                    QDomElement photoTag = doc.createElement("photo");
                    QDomText photoText = doc.createTextNode((*iterBlips)->filepath);
                    photoTag.appendChild(photoText);
                    
                    QDomElement titleTag = doc.createElement("title");
                    QDomText titleText = doc.createTextNode((*iterBlips)->title);
                    titleTag.appendChild(titleText);
                    
                    QDomElement descriptionTag = doc.createElement("description");
                    QDomText descriptionText = doc.createTextNode((*iterBlips)->description);
                    descriptionTag.appendChild(descriptionText);
                    
                    QDomElement tagsTag = doc.createElement("tags");
                    QDomText tagsText = doc.createTextNode((*iterBlips)->tags);
                    tagsTag.appendChild(tagsText);
                    
                    blipTag.appendChild(dateTag);
                    blipTag.appendChild(photoTag);
                    blipTag.appendChild(titleTag);
                    blipTag.appendChild(descriptionTag);
                    blipTag.appendChild(tagsTag);
                }
                
                // Get XML as String and write to text file.
                QString xml = doc.toString();
                
                QFile outBUPFile(outFile);
                if (outBUPFile.open(QFile::WriteOnly | QFile::Truncate)) 
                {
                    QTextStream outBUPStream(&outBUPFile);
                    outBUPStream << xml;
                    outBUPFile.flush();
                    outBUPFile.close();
                }
            }
		}

    }
    
    void BlipUpInterface::openBlips()
    {
        QFileDialog fileDialog;
		fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
		fileDialog.setWindowTitle("Open Blips");
        fileDialog.setFileMode(QFileDialog::ExistingFiles);
		
		QStringList filters;
		filters << "BUP File (*.bup)";
		fileDialog.setNameFilters(filters);
		if(fileDialog.exec() == QDialog::Accepted)
		{
            currentBlip = NULL;
			QStringList files = fileDialog.selectedFiles();
            if(files.size() == 1)
            {
                QString inFile = files[0];
                cout << "Input File = " << inFile.toStdString() << endl;
                
                QDomDocument doc("BlipUpDoc");
                QFile inBUPFile(inFile);
                if (!inBUPFile.open(QIODevice::ReadOnly))
                {
                    return;
                }
                if (!doc.setContent(&inBUPFile)) 
                {
                    inBUPFile.close();
                    return;
                }
                inBUPFile.close();
                
                QDomElement docElem = doc.documentElement();
                
                QDomNode n = docElem.firstChild();
                while(!n.isNull()) 
                {
                    QDomElement e = n.toElement(); // try to convert the node to an element.
                    if((!e.isNull()) && (e.tagName() == "blip")) 
                    {
                        //cout << qPrintable(e.tagName()) << endl; // the node really is an element.
                        QDomNodeList childNodes = n.childNodes();
                        
                        if(childNodes.count() == 5)
                        {
                            QDomNode dateNode;
                            QDomNode photoNode;
                            QDomNode titleNode;
                            QDomNode descriptionNode;
                            QDomNode tagsNode;
                            
                            QDomNode bn = e.firstChild();
                            while(!bn.isNull()) 
                            {
                                QDomElement be = bn.toElement(); // try to convert the node to an element.
                                if((!be.isNull()) && (be.tagName() == "date")) 
                                {
                                    dateNode = bn;
                                }
                                else if((!be.isNull()) && (be.tagName() == "photo"))
                                {
                                    photoNode = bn;
                                }
                                else if((!be.isNull()) && (be.tagName() == "title"))
                                {
                                    titleNode = bn;
                                }
                                else if((!be.isNull()) && (be.tagName() == "description"))
                                {
                                    descriptionNode = bn;
                                }
                                else if((!be.isNull()) && (be.tagName() == "tags"))
                                {
                                    tagsNode = bn;
                                }
                                
                                bn = bn.nextSibling();
                            }
                            
                            QString dateText = "";
                            QString photoText = "";
                            QString titleText = "";
                            QString descriptionText = "";
                            QString tagsText = "";
                            
                            if(dateNode.firstChild().isText())
                            {
                                dateText = dateNode.firstChild().toText().nodeValue();
                            }
                            
                            if(photoNode.firstChild().isText())
                            {
                                photoText = photoNode.firstChild().toText().nodeValue();
                            }
                            
                            if(titleNode.firstChild().isText())
                            {
                                titleText = titleNode.firstChild().toText().nodeValue();
                            }
                            
                            if(descriptionNode.firstChild().isText())
                            {
                                descriptionText = descriptionNode.firstChild().toText().nodeValue();
                            }
                            
                            if(dateNode.firstChild().isText())
                            {
                                tagsText = tagsNode.firstChild().toText().nodeValue();
                            }
                            
                            cout << "Blip:\n";
                            cout << "\tDate: " << dateText.toStdString() << endl;
                            cout << "\tFilepath: " << photoText.toStdString() << endl;
                            cout << "\tTitle: " << titleText.toStdString() << endl;
                            cout << "\tDescription: " << descriptionText.toStdString() << endl;
                            cout << "\tTags: " << tagsText.toStdString() << endl;
                            
                            BlipDetails *blip = new BlipDetails();
                            blip->label = dateText;
                            blip->filepath = photoText;
                            blip->date = QDateTime::fromString(dateText, "yyyy-MM-dd");
                            blip->title = titleText;
                            blip->description = descriptionText;
                            blip->tags = tagsText;
                            
                            blips->push_back(blip);
                            currentBlip = blip;
                            
                            QListWidgetItem *newItem = new QListWidgetItem;
                            newItem->setText(blip->label);
                            blipList->insertItem(0, newItem);
                        }
                        
                    }
                    n = n.nextSibling();
                }
                
            }
            
            if(currentBlip != NULL)
            {
                descriptionTextEdit->setPlainText(currentBlip->description);
                titleTextLine->setText(currentBlip->title);
                tagsTextLine->setText(currentBlip->tags);
                if(currentImage == NULL)
                {
                    currentImage = new QImage;
                }
                currentImage->load(currentBlip->filepath);
                imageView->setPixmap(QPixmap::fromImage(currentImage->scaledToWidth(imageView->width(), Qt::SmoothTransformation)));
            }
		}

    }
    
    void BlipUpInterface::selectBlipInList(QListWidgetItem *item)
    {
        if(currentBlip != NULL)
        {
            currentBlip->title = titleTextLine->text();
            currentBlip->description = descriptionTextEdit->toPlainText();
            currentBlip->tags = tagsTextLine->text();
        }
        
        QString label = item->text();
        for(vector<BlipDetails*>::iterator iterBlips = blips->begin(); iterBlips != blips->end(); ++iterBlips)
        {
            if((*iterBlips)->label == label)
            {
                currentBlip = (*iterBlips);
                descriptionTextEdit->setPlainText(currentBlip->description);
                titleTextLine->setText(currentBlip->title);
                tagsTextLine->setText(currentBlip->tags);
                if(currentImage == NULL)
                {
                    currentImage = new QImage;
                }
                currentImage->load(currentBlip->filepath);
                imageView->setPixmap(QPixmap::fromImage(currentImage->scaledToWidth(imageView->width(), Qt::SmoothTransformation)));
            }
        }
    }
    
    void BlipUpInterface::login()
    {
        if(!authenticationSet)
        {
            // Authenticate...
            BlipUpAuthentic *blipUpAuth = new BlipUpAuthentic(this, this);
            if(blipUpAuth->exec() == QDialog::Accepted)
            {
                // Check that authentication is now setup!
                
                // If not throw error!
            }
            
            if(authenticationSet)
            {
                QString usernameText = QString("You are currently login in as ") + username; 
                usernameLabel->setText(usernameText);
                loginButton->setEnabled(false);
                logoutButton->setEnabled(true);
            }
        }
    }
    
    void BlipUpInterface::logout()
    {
        progSettings->beginGroup("UserInfo");
		progSettings->setValue("Username", "");
		progSettings->setValue("PassToken", "");
		progSettings->endGroup();
        
        authenticationSet = false;
        username = "";
        passToken = "";
        
        usernameLabel->setText("You are not currently login...");
        loginButton->setEnabled(true);
        logoutButton->setEnabled(false);
    }
   
    
    BlipUpInterface::~BlipUpInterface()
    {
        if(currentImage != NULL)
        {
            delete currentImage;
        }
    }
    
    BlipUpAuthentic::BlipUpAuthentic(QWidget *parent, BlipUpInterface *mainInterface): QDialog(parent)
    {
        this->mainInterface = mainInterface;
        
        QPushButton *goToAuthURLButton = new QPushButton("Step 1: Get Code");
        connect(goToAuthURLButton, SIGNAL(clicked()), this, SLOT(goToAuthURL()));
        
        codeTextLine = new QLineEdit();
        
        QPushButton *OKButton = new QPushButton("OK");
        connect(OKButton, SIGNAL(clicked()), this, SLOT(OKSlot()));
        
        /**************** SETUP Final Layout ****************/
		QVBoxLayout *layout = new QVBoxLayout();
		layout->insertWidget(1, goToAuthURLButton);
        layout->insertWidget(2, new QLabel("Step 2: Code:"));
        layout->insertWidget(3, codeTextLine);
		layout->insertWidget(4, OKButton);
		setLayout(layout);
		/**************** END Final Layout ****************/
    }
    
    
    void BlipUpAuthentic::goToAuthURL()
    {
        QDesktopServices deskService;
        deskService.openUrl(QUrl("http://www.blipfoto.com/getpermission/987528"));
    }
    
    void BlipUpAuthentic::OKSlot()
    {
        QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
        connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyAuthFinished(QNetworkReply*)));
        
        QString authUrlStr = QString("http://api.blipfoto.com/get/token/?api_key=") + apiStr + QString("&version=2") + QString("&temp_token=") + codeTextLine->text();
        
        //cout << "URL: " << authUrlStr.toStdString() << endl;
        
        netManager->get(QNetworkRequest(QUrl(authUrlStr)));
    }
    
    void BlipUpAuthentic::replyAuthFinished(QNetworkReply *authReply)
    {
        if(authReply->error() == QNetworkReply::NoError)
        {
            //cout << "Request was successful - get data from reply!\n";
            QByteArray bytes = authReply->readAll();  // bytes
            QString replyStr(bytes);
            
            mainInterface->setAuthXML(replyStr);
            emit accept();
        }
        else
        {
            cout << "An error occurred :( = " << authReply->error() << endl;
        }
    }
    
    BlipUpAuthentic::~BlipUpAuthentic()
    {
        
    }
    
    
    
    BlipUpSubmittingDialog::BlipUpSubmittingDialog(QWidget *parent, vector<BlipDetails*> *blips, QString username, QString passToken):QDialog(parent)
    {
        this->blips = blips;
        this->username = username;
        this->passToken = passToken;
        
        setMinimumSize(500, 300);
        
        feedbackText = new QPlainTextEdit(this);
        feedbackText->setReadOnly(true);
        numOfBlipsProgress = new QProgressBar(this);
        numOfBlipsProgress->setMinimum(0);
        numOfBlipsProgress->setMaximum(blips->size());
        numOfBlipsProgress->setValue(0);
        numOfBlipsProgress->setTextVisible(true);
        blipUploadProgress = new QProgressBar(this);
        blipUploadProgress->setMinimum(0);
        blipUploadProgress->setMaximum(100);
        blipUploadProgress->setValue(0);
        blipUploadProgress->setTextVisible(true);
        
        closeButton = new QPushButton("Close");
        connect(closeButton, SIGNAL(clicked()), this, SLOT(closeSlot()));
        closeButton->setEnabled(false);
        
        /**************** SETUP Final Layout ****************/
		QVBoxLayout *layout = new QVBoxLayout();
        layout->insertWidget(1, new QLabel("Submitting:"));
		layout->insertWidget(2, numOfBlipsProgress);
        layout->insertWidget(3, new QLabel("Upload:"));
        layout->insertWidget(4, blipUploadProgress);
        layout->insertWidget(5, feedbackText);
        layout->insertWidget(6, closeButton);
		setLayout(layout);
		/**************** END Final Layout ****************/
        
        feedbackText->appendPlainText("Starting...\n");
        numOfBlipsProgress->setValue(1);
        currentBlipIdx = 0;
        
        gettingTimeStampToCheckDataAvailable = true;
        
        QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
        connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyGetTimeStampFinished(QNetworkReply*)));
        QString blipTimeUrlStr = QString("http://api.blipfoto.com/get/time/?api_key=") + apiStr + QString("&version=2");
        netManager->get(QNetworkRequest(QUrl(blipTimeUrlStr)));
        
        feedbackText->appendPlainText(QString("Uploading entry ") + blips->at(currentBlipIdx)->label);
    }
    
    void BlipUpSubmittingDialog::closeSlot()
    {
        emit accept();
    }
    
    void BlipUpSubmittingDialog::replyGetTimeStampFinished(QNetworkReply *reply)
    {
        BlipUpXMLParsing parseXML;
        if(reply->error() == QNetworkReply::NoError)
        {
            QByteArray bytes = reply->readAll();  // bytes
            QString replyXMLStr(bytes);
            
            QString timeStampStr;
            try 
            {
                if(parseXML.parseTimeXML(replyXMLStr, &timeStampStr))
                {
                    if(gettingTimeStampToCheckDataAvailable)
                    {
                        gettingTimeStampToCheckDataAvailable = false;
                        
                        QString uid = QUuid::createUuid().toString();
                        QString nonceStr = QString(QCryptographicHash::hash(uid.toAscii(),QCryptographicHash::Md5).toHex());
                        QString sigToBeHashed = timeStampStr + nonceStr + passToken + secertStr;
                        QString signatureStr = QString(QCryptographicHash::hash(sigToBeHashed.toAscii(),QCryptographicHash::Md5).toHex());
                        
                        QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
                        connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyDateAvailableFinished(QNetworkReply*)));
                        
                        QString dateTimeUrlStr = QString("http://api.blipfoto.com/get/datevalidation/?api_key=") + apiStr 
                                               + QString("&timestamp=") + timeStampStr 
                                               + QString("&nonce=") + nonceStr 
                                               + QString("&token=") + passToken
                                               + QString("&signature=") + signatureStr
                                               + QString("&entry_date=") + blips->at(currentBlipIdx)->label;

                        netManager->get(QNetworkRequest(QUrl(dateTimeUrlStr)));
                    }
                    else if(gettingTimeStampToSubmitBlip)
                    {
                        gettingTimeStampToSubmitBlip = false;
                        
                        QString uid = QUuid::createUuid().toString();
                        QString nonceStr = QString(QCryptographicHash::hash(uid.toAscii(),QCryptographicHash::Md5).toHex());
                        QString sigToBeHashed = timeStampStr + nonceStr + passToken + secertStr;
                        QString signatureStr = QString(QCryptographicHash::hash(sigToBeHashed.toAscii(),QCryptographicHash::Md5).toHex());
                        
                        QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
                        multiPart->setBoundary(QString("------------------------------------sdkfhsdjkfhsduvbiufdkjnSAIPUH").toAscii());
                        
                        QHttpPart titlePart;
                        titlePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
                        titlePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"entry_title\""));
                        titlePart.setBody(blips->at(currentBlipIdx)->title.toAscii());
                        
                        QHttpPart descriptionPart;
                        descriptionPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
                        descriptionPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"entry_description\""));
                        descriptionPart.setBody(blips->at(currentBlipIdx)->description.toAscii());
                        
                        QHttpPart tagsPart;
                        tagsPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
                        tagsPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"entry_tags\""));
                        tagsPart.setBody(blips->at(currentBlipIdx)->tags.toAscii());
                        
                        QHttpPart datePart;
                        datePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
                        datePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"entry_date\""));
                        datePart.setBody(blips->at(currentBlipIdx)->label.toAscii());
                        
                        QHttpPart imagePart;
                        imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
                        imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image_upload\"; filename=\"imageupload\""));                        
                        QFile *file = new QFile(blips->at(currentBlipIdx)->filepath);
                        file->open(QIODevice::ReadOnly);
                        imagePart.setBodyDevice(file);
                        file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart

                        multiPart->append(imagePart);
                        multiPart->append(titlePart);
                        multiPart->append(descriptionPart);
                        multiPart->append(tagsPart);
                        multiPart->append(datePart);
                                                
                        QString submitBlipUrlStr = QString("http://api.blipfoto.com/post/entry/?api_key=") + apiStr 
                                                 + QString("&timestamp=") + timeStampStr 
                                                 + QString("&nonce=") + nonceStr 
                                                 + QString("&token=") + passToken
                                                 + QString("&signature=") + signatureStr;
                        
                        QUrl url(submitBlipUrlStr);
                        QNetworkRequest request(url);
                        
                        blipUploadProgress->setValue(0);
                        QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
                        replyBlipUpload = netManager->post(request, multiPart);
                        connect(replyBlipUpload, SIGNAL(finished()), this, SLOT(replyBlipUploadedFinished()));
                        connect(replyBlipUpload, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(blipUploadProgressSlot(qint64, qint64)));
                        connect(replyBlipUpload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(blipUploadErrorSlot(QNetworkReply::NetworkError)));
                        
                        multiPart->setParent(replyBlipUpload);
                        
                    }
                    else
                    {
                        feedbackText->appendPlainText("Do not know what to do with reply for retriving time stamp.");
                        closeButton->setEnabled(true);
                    }
                }
                else
                {
                    // Do something with error!
                    QString error = parseXML.getErrorMessage(replyXMLStr);
                    //cerr << "ERROR: " << error.toStdString() << endl;
                    feedbackText->appendPlainText(QString("Error: ") + error);
                    closeButton->setEnabled(true);
                }
            } 
            catch (BlipUpException &e) 
            {
                // Do something with error!
                //cerr << "ERROR: " << e.what() << endl;
                feedbackText->appendPlainText(QString("Error: ") +  QString::fromStdString(e.what()));
                closeButton->setEnabled(true);
            }
        }
        else
        {
            QByteArray bytes = reply->readAll();  // bytes
            QString replyXMLStr(bytes);
            
            QString error = parseXML.getErrorMessage(replyXMLStr);
            feedbackText->appendPlainText(QString("A blipfoto error: ") + error);
            feedbackText->appendPlainText(QString("A http error: ") + getHTTReplyErrMessage(reply->error()));
            
            closeButton->setEnabled(true);
        }
    }
    
    void BlipUpSubmittingDialog::replyDateAvailableFinished(QNetworkReply *reply)
    {
        BlipUpXMLParsing parseXML;
        if(reply->error() == QNetworkReply::NoError)
        {
            QByteArray bytes = reply->readAll();  // bytes
            QString replyXMLStr(bytes);
                        
            try 
            {
                bool dateAvailable = false;
                
                if(parseXML.parseDateAvailableXML(replyXMLStr, &dateAvailable))
                {
                    if(dateAvailable)
                    {
                        gettingTimeStampToCheckDataAvailable = false;
                        gettingTimeStampToSubmitBlip = true;
                        
                        QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
                        connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyGetTimeStampFinished(QNetworkReply*)));
                        QString blipTimeUrlStr = QString("http://api.blipfoto.com/get/time/?api_key=") + apiStr + QString("&version=2");
                        netManager->get(QNetworkRequest(QUrl(blipTimeUrlStr)));
                    }
                    else
                    {
                        feedbackText->appendPlainText(QString("Date ") + blips->at(currentBlipIdx)->label + QString(" is not available."));
                        closeButton->setEnabled(true);
                    }
                }
                else
                {
                    // Do something with error!
                    QString error = parseXML.getErrorMessage(replyXMLStr);
                    //cerr << "ERROR: " << error.toStdString() << endl;
                    feedbackText->appendPlainText(QString("Error: ") + error);
                    closeButton->setEnabled(true);
                }
            } 
            catch (BlipUpException &e) 
            {
                // Do something with error!
                //cerr << "ERROR: " << e.what() << endl;
                feedbackText->appendPlainText(QString("Error: ") +  QString::fromStdString(e.what()));
                closeButton->setEnabled(true);
            }
            
        }
        else
        {
            QByteArray bytes = reply->readAll();  // bytes
            QString replyXMLStr(bytes);
            
            QString error = parseXML.getErrorMessage(replyXMLStr);
            feedbackText->appendPlainText(QString("A blipfoto error: ") + error);
            feedbackText->appendPlainText(QString("A http error: ") + getHTTReplyErrMessage(reply->error()));
            
            closeButton->setEnabled(true);
        }
    }
    
    void BlipUpSubmittingDialog::replyBlipUploadedFinished()
    {
        BlipUpXMLParsing parseXML;
        if(replyBlipUpload->error() == QNetworkReply::NoError)
        {
            QByteArray bytes = replyBlipUpload->readAll();  // bytes
            QString replyXMLStr(bytes);
            
            QString message = "";
            if(parseXML.parseBlipUploadXML(replyXMLStr, &message))
            {
                feedbackText->appendPlainText(QString("Blip Uploaded: ") + message);
                if(currentBlipIdx == (blips->size()-1))
                {
                    feedbackText->appendPlainText(QString("\nAll Blips have now been uploaded :)"));
                    closeButton->setEnabled(true);
                }
                else
                {
                    ++currentBlipIdx;
                    numOfBlipsProgress->setValue(currentBlipIdx+1);
                    
                    gettingTimeStampToCheckDataAvailable = true;
                    
                    QNetworkAccessManager *netManager = new QNetworkAccessManager(this);
                    connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyGetTimeStampFinished(QNetworkReply*)));
                    QString blipTimeUrlStr = QString("http://api.blipfoto.com/get/time/?api_key=") + apiStr + QString("&version=2");
                    netManager->get(QNetworkRequest(QUrl(blipTimeUrlStr)));
                    
                    feedbackText->appendPlainText(QString("Uploading entry ") + blips->at(currentBlipIdx)->label);
                }
            }
            else
            {
                QString error = parseXML.getErrorMessage(replyXMLStr);
                feedbackText->appendPlainText(QString("A blipfoto error: ") + error);

                closeButton->setEnabled(true);
            }
            
        }
        else
        {
            QByteArray bytes = replyBlipUpload->readAll();  // bytes
            QString replyXMLStr(bytes);
            
            QString error = parseXML.getErrorMessage(replyXMLStr);
            feedbackText->appendPlainText(QString("A blipfoto error: ") + error);
            feedbackText->appendPlainText(QString("A http error: ") + getHTTReplyErrMessage(replyBlipUpload->error()));
            
            closeButton->setEnabled(true);

        }
    }
    
    void BlipUpSubmittingDialog::blipUploadProgressSlot(qint64 bytesSent, qint64 bytesTotal)
    {
        blipUploadProgress->setMaximum(bytesTotal);
        blipUploadProgress->setValue(bytesSent);
    }
    
    void BlipUpSubmittingDialog::blipUploadErrorSlot(QNetworkReply::NetworkError code)
    {
        closeButton->setEnabled(true);
    }
    
    BlipUpSubmittingDialog::~BlipUpSubmittingDialog()
    {
        
    }
    
    bool BlipUpXMLParsing::parseAuthXML(QString blipXML, QString *username, QString *passToken) throw(BlipUpException)
    {
        if(!this->checkForError(blipXML))
        {
            try 
            {
                QDomNode dataNode = this->getData(blipXML);
                
                QDomNodeList displaNameNodes = dataNode.toElement().elementsByTagName("display_name");
                if(displaNameNodes.count() != 1)
                {
                    // Parsing ERROR Occured
                    throw BlipUpException("The number of display_name tags wasn't equal to 1.");
                }
                else
                {
                    if( displaNameNodes.at(0).hasChildNodes() )
                    {
                        *username = displaNameNodes.at(0).firstChild().toText().nodeValue();
                    }
                    else
                    {
                        // Parsing ERROR Occured
                        throw BlipUpException("The display_name tag did not contain any information.");
                    }
                    
                }
                
                QDomNodeList tokenNodes = dataNode.toElement().elementsByTagName("token");
                if(tokenNodes.count() != 1)
                {
                    // Parsing ERROR Occured
                    throw BlipUpException("The number of token tags wasn't equal to 1.");
                }
                else
                {
                    if( tokenNodes.at(0).hasChildNodes() )
                    {
                        *passToken = tokenNodes.at(0).firstChild().toText().nodeValue();
                    }
                    else
                    {
                        // Parsing ERROR Occured
                        throw BlipUpException("The token tag did not contain any information.");
                    }
                    
                }
            } 
            catch (BlipUpException &e) 
            {
                throw e;
            }
        }
        else
        {
            return false;
        }
        
        return true;
    }
    
    bool BlipUpXMLParsing::parseTimeXML(QString blipXML, QString *timeStamp) throw(BlipUpException)
    {
        if(!this->checkForError(blipXML))
        {
            try 
            {
                QDomNode dataNode = this->getData(blipXML);
                
                QDomNodeList timestampNodes = dataNode.toElement().elementsByTagName("timestamp");
                if(timestampNodes.count() != 1)
                {
                    // Parsing ERROR Occured
                    throw BlipUpException("The number of timestamp tags wasn't equal to 1.");
                }
                else
                {
                    if( timestampNodes.at(0).hasChildNodes() )
                    {
                        *timeStamp = timestampNodes.at(0).firstChild().toText().nodeValue();
                    }
                    else
                    {
                        // Parsing ERROR Occured
                        throw BlipUpException("The timestamp tag did not contain any information.");
                    }
                    
                }
            } 
            catch (BlipUpException &e) 
            {
                throw e;
            }
        }
        else
        {
            return false;
        }
        
        return true;
    }
    
    bool BlipUpXMLParsing::parseDateAvailableXML(QString blipXML, bool *available) throw(BlipUpException)
    {
        if(!this->checkForError(blipXML))
        {
            try 
            {
                QDomNode dataNode = this->getData(blipXML);
                
                QDomNodeList timestampNodes = dataNode.toElement().elementsByTagName("success");
                if(timestampNodes.count() != 1)
                {
                    // Parsing ERROR Occured
                    throw BlipUpException("The number of success tags wasn't equal to 1.");
                }
                else
                {
                    if( timestampNodes.at(0).hasChildNodes() )
                    {
                        *available = true;
                    }
                    else
                    {
                        // Parsing ERROR Occured
                        throw BlipUpException("The success tag did not contain any information.");
                    }
                    
                }
            } 
            catch (BlipUpException &e) 
            {
                throw e;
            }
        }
        else
        {
            return false;
        }
        
        return true;
    }
    
    bool BlipUpXMLParsing::parseBlipUploadXML(QString blipXML, QString *message) throw(BlipUpException)
    {
        if(!this->checkForError(blipXML))
        {
            try 
            {
                QDomNode dataNode = this->getData(blipXML);
                
                QDomNodeList messageNodes = dataNode.toElement().elementsByTagName("result");
                if(messageNodes.count() != 1)
                {
                    // Parsing ERROR Occured
                    throw BlipUpException("The number of result tags wasn't equal to 1.");
                }
                else
                {
                    if( messageNodes.at(0).hasChildNodes() )
                    {
                        *message = messageNodes.at(0).firstChild().toText().nodeValue();
                    }
                    else
                    {
                        // Parsing ERROR Occured
                        throw BlipUpException("The result tag did not contain any information.");
                    }
                    
                }
            } 
            catch (BlipUpException &e) 
            {
                throw e;
            }
        }
        else
        {
            return false;
        }
        
        return true;
    }
    
    bool BlipUpXMLParsing::checkForError(QString blipXML) throw(BlipUpException)
    {
        QDomDocument doc("BlipXMLDoc");
        doc.setContent(blipXML, false);
        
        // Check whether an error occured.
        bool errorOccurred = false;
        QDomNodeList errorNodes = doc.elementsByTagName("error");
        QDomNode node;
        for(int i = 0; i < errorNodes.count(); ++i)
        {
            if( errorNodes.at(i).hasChildNodes() )
            {
                // Blip Error Occured
                errorOccurred = true;
            }
        }
        
        return errorOccurred;
    }
    
    QString BlipUpXMLParsing::getErrorMessage(QString blipXML) throw(BlipUpException)
    {
        QDomDocument doc("BlipXMLDoc");
        doc.setContent(blipXML, false);
        
        // Check whether an error occured.
        bool errorOccurred = false;
        QString errMessage = "";
        QDomNodeList errorNodes = doc.elementsByTagName("message");
        QDomNode node;
        for(int i = 0; i < errorNodes.count(); ++i)
        {
            if( errorNodes.at(i).hasChildNodes() )
            {
                // Blip Error Occured
                errorOccurred = true;
                errMessage += errorNodes.at(i).firstChild().toText().nodeValue();
            }
        }
        
        return errMessage;
    }
    
    unsigned int BlipUpXMLParsing::getErrorCode(QString blipXML) throw(BlipUpException)
    {
        QDomDocument doc("BlipXMLDoc");
        doc.setContent(blipXML, false);
        
        // Check whether an error occured.
        bool errorOccurred = false;
        QString errMessage = "";
        QDomNodeList errorNodes = doc.elementsByTagName("code");
        QDomNode node;
        for(int i = 0; i < errorNodes.count(); ++i)
        {
            if( errorNodes.at(i).hasChildNodes() )
            {
                // Blip Error Occured
                errorOccurred = true;
                errMessage += errorNodes.at(i).firstChild().toText().nodeValue();
            }
        }
        
        unsigned int errCode = errMessage.toUInt();
        
        return errCode;
    }
    
    QDomNode BlipUpXMLParsing::getData(QString blipXML) throw(BlipUpException)
    {
        QDomDocument doc("BlipXMLDoc");
        doc.setContent(blipXML, false);
        
        // Check whether an error occured.
        bool errorOccurred = false;
        QDomNodeList errorNodes = doc.elementsByTagName("error");
        QDomNode node;
        for(int i = 0; i < errorNodes.count(); ++i)
        {
            if( errorNodes.at(i).hasChildNodes() )
            {
                // Blip Error Occured
                errorOccurred = true;
            }
        }
        
        QDomNode dataNode;
        
        if(!errorOccurred)
        {            
            QDomNodeList dataNodes = doc.elementsByTagName("data");
            if(dataNodes.count() != 1)
            {
                // Parsing ERROR Occured
                throw BlipUpException("An error occurred parsing responce for data tag from blipfoto.");
            }
            else
            {
                dataNode = dataNodes.at(0);
            }
        }
        else
        {
            throw BlipUpException("An error occurred in the responce from blipfoto.");
        }
        
        return dataNode;
    };
    
    
}


